package com.pet.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pet.system.constant.ResourceType;
import com.pet.system.domain.entity.SysResource;
import com.pet.system.domain.entity.SysRoleResource;
import com.pet.system.domain.entity.SysUserResource;
import com.pet.system.mapper.SysResourceMapper;
import com.pet.system.mapper.SysRoleResourceMapper;
import com.pet.system.mapper.SysUserResourceMapper;
import com.pet.system.service.ISysResourceService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;

/** @author Centaurea */
@Service
@AllArgsConstructor
public class SysResourceServiceImpl implements ISysResourceService {
  private final SysResourceMapper resourceMapper;
  private final SysRoleResourceMapper roleResourceMapper;
  private final SysUserResourceMapper userResourceMapper;

  @Override
  public boolean add(SysResource entity) {
    this.validate(entity);
    int i = resourceMapper.insert(entity);
    return i == 1;
  }

  @Override
  public boolean update(SysResource entity) {
    this.validate(entity);
    if (entity.getId() == null) {
      resourceMapper.insert(entity);
    } else {
      resourceMapper.updateById(entity);
    }
    return true;
  }

  private void validate(SysResource entity) {
    if (entity.getType() == ResourceType.URL.getType()) {
      // 如果待插入数据type = 1(菜单), 这里校验 parentId 的 type 也必须为 1
      if (entity.getParentId() != null && entity.getParentId() != 0L) {
        SysResource parentResource = resourceMapper.selectById(entity.getParentId());
        if (parentResource.getType() != ResourceType.URL.getType()) {
          throw new IllegalArgumentException("归属菜单不合法");
        }
      }
      // url 和 组件地址 不可空
      if (StringUtils.isEmpty(entity.getUrl())) {
        throw new IllegalArgumentException("菜单URL不合法");
      }
      if (StringUtils.isEmpty(entity.getPath())) {
        throw new IllegalArgumentException("组件地址不合法");
      }
    } else if (entity.getType() == ResourceType.BUTTON.getType()) {
      // 按钮 必须从属于某个菜单
      if (entity.getParentId() == null) {
        throw new IllegalArgumentException("归属菜单不合法");
      }
    } else {
      throw new IllegalArgumentException("暂不支持的资源类型");
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean delete(List<Integer> resourceIds) {
    // 删除 角色资源关系、删除自身&所有子级关系
    // 获取资源下所有子级资源, 再加上本身资源节点 批量删除
    List<SysResource> all = resourceMapper.selectList(null);
    List<SysResource> list = new ArrayList<>();
    for (Integer resourceId : resourceIds) {
      sortSysResourceList(resourceId, all, list);
    }
    list.forEach(r -> resourceIds.add(r.getId()));
    for (Integer resourceId : resourceIds) {
      QueryWrapper<SysUserResource> queryWrapper1 = new QueryWrapper<>();
      queryWrapper1.eq(SysUserResource.COL_RESOURCE_ID, resourceId);
      userResourceMapper.delete(queryWrapper1);
      QueryWrapper<SysRoleResource> queryWrapper2 = new QueryWrapper<>();
      queryWrapper2.eq(SysRoleResource.COL_RESOURCE_ID, resourceId);
      roleResourceMapper.delete(queryWrapper2);
      resourceMapper.deleteBatchIds(resourceIds);
    }
    return true;
  }

  @Override
  public SysResource get(Serializable id) {
    return resourceMapper.selectById(id);
  }

  @Override
  public List<SysResource> queryList(Map<String, Object> params) {
    QueryWrapper<SysResource> queryWrapper = new QueryWrapper<>();
    if (params.get("status") != null) {
      queryWrapper.eq(SysResource.COL_STATUS, params.get("status"));
    }
    if (params.get("parentId") != null) {
      queryWrapper.eq(SysResource.COL_PARENT_ID, params.get("parentId"));
    }
    if (params.get("type") != null) {
      queryWrapper.eq(SysResource.COL_TYPE, params.get("type"));
    }
    if (params.get("searchWord") != null) {
      queryWrapper.like(SysResource.COL_NAME, params.get("searchWord"));
    }
    return resourceMapper.selectList(queryWrapper);
  }

  private void sortSysResourceList(
      Integer parentId, List<SysResource> all, List<SysResource> list) {
    for (SysResource resource : all) {
      if (resource.getParentId().equals(parentId)) {
        list.add(resource);
        if (all.stream().anyMatch(r -> r.getParentId().equals(resource.getId()))) {
          sortSysResourceList(resource.getId(), all, list);
        }
      }
    }
  }

  @Override
  public JSONArray queryTree(Map<String, Object> params) {
    List<SysResource> all = queryList(params);
    Set<Integer> parentIds = new HashSet<>();
    all.forEach(
        r -> {
          parentIds.add(r.getParentId());
        });
    JSONArray array = new JSONArray();
    transSysResourceTree(
        params.get("parentId") == null ? 0 : Integer.parseInt(params.get("parentId").toString()),
        all,
        array,
        parentIds);
    return array;
  }

  private void transSysResourceTree(
      Integer parentId, List<SysResource> all, JSONArray array, Set<Integer> parentIds) {
    for (SysResource resource : all) {
      if (resource.getParentId().equals(parentId)) {
        JSONObject parent =
            JSON.parseObject(JSON.toJSONString(resource, SerializerFeature.WriteMapNullValue));
        array.add(parent);
        if (!parentIds.contains(resource.getId())) {
          parent.put("children", null);
          continue;
        }
        JSONArray children = new JSONArray();
        parent.put("children", children);
        transSysResourceTree(resource.getId(), all, children, parentIds);
      }
    }
  }
}
